import { Body, Controller, Delete, Get, Param, ParseIntPipe, Post, Put, Req } from '@nestjs/common';
import { DtoPipe } from '../../pipes/dto/dto.pipe';
import { DbService } from '@app/db';
import { Menu } from '@app/db/common/entities/Menu';
import { FindOptionsWhere, In } from 'typeorm';
import { BaseController } from '../../base/base.controller';
import { AddDto, EditDto } from './dto';
import { MenuService } from './menu.service';

@Controller('menu')
export class MenuController extends BaseController{
    constructor(
        private db:DbService,
        private service:MenuService
    ) {
        super()
    }


    @Get('permission')
    async permission(@Req() {userId, isSuper}) {
        let where:FindOptionsWhere<Menu> = {
            enable : true
        }

        let menu:Menu[] = []

        if(!isSuper) {
            let menuIds = await this.service.getPermission(userId)
            if(!menuIds || menuIds.length == 0) return this.successRes(menu)
            where = {
                id : In(menuIds)
            }
        }

        

        menu = await this.db.menu.find(where, ['id', 'path', 'name', 'type', 'component', 'permission', 'keepAlive', 'display', 'sort', 'parentId'], null, null, {sort : 'ASC', id : 'ASC'})

        return this.successRes(menu)
    }


    @Get('list')
    async list(@Req() {userId, isSuper}) {
        let list = []
        let where:FindOptionsWhere<Menu> = null

        if(!isSuper) {
            where = {
                id : In(await this.service.getPermission(userId))
            }
        }
        
        list = await this.db.menu.find(where, null, null, null, {sort : 'ASC', id : 'ASC'})
  
        return this.successRes(list)
    }
    
    @Post('add')
    async add(@Body(new DtoPipe()) dto:AddDto, @Req() { locale }) {
        //判断是否存在了相同的菜单名
        if(true == await this.db.menu.isExistsByWhere({name : dto.name, parentId : dto.parentId})) {
            return this.failRes(this.i18n.t(locale, 'nameIsExists'))
        }

        //判断是否存在了相同的路径
        if((dto.type === 'FOLD' || dto.type === 'PAGE') && true == await this.db.menu.isExistsByWhere({path : dto.path, parentId : dto.parentId})) {
            return this.failRes(this.i18n.t(locale, 'pathIsExists'))
        }

        if(dto.type === 'BUTTON') {
            delete dto.component
            delete dto.display
            delete dto.path
            delete dto.keepAlive
            delete dto.sort
        }

        const res = await this.db.menu.insert(dto)
        return res ? this.successRes(res.rows) : this.failRes()
    }

    @Put('edit/:id')
    async edit(@Body(new DtoPipe({skipMissingProperties : true})) dto:EditDto, @Param('id', ParseIntPipe) id:number, @Req() { locale }) {
        if(id <= 0) return

        let fields = Object.keys(dto) as (keyof Menu)[]
        if(fields.length == 0) return
        fields.push('parentId')


        const menu = await this.db.menu.findOne({ id }, fields)
        
        if(!menu) return

        let updateData:{[key in keyof Menu]? : Menu[key]} = {}

        const parentId = menu.parentId
        delete menu.parentId

        for(let k in menu) {
            if(menu[k] != dto[k]) {
                updateData[k] = dto[k]
            }
        }

        if(Object.keys(updateData).length == 0) return this.successRes()

        if(updateData.name && (true == await this.db.menu.isExistsByWhere({name : updateData.name, parentId : parentId}))) {
            return this.failRes(this.i18n.t(locale, 'nameIsExists'))
        }

        if(updateData.path && (true == await this.db.menu.isExistsByWhere({path : updateData.path, parentId : parentId}))) {
            return this.failRes(this.i18n.t(locale, 'pathIsExists'))
        }

        const res = await this.db.menu.update({id : id}, updateData)
        return res === 0 ? this.failRes() : this.successRes()
    }

    @Delete('delete/:id')
    async delete(@Param('id', ParseIntPipe) id:number, @Req() { locale }) {
        if(id <= 0) return
        if((await this.db.menu.isExistsByWhere({parentId : id}))) return this.failRes(this.i18n.t(locale, 'menuHashChildNotDel'))
        const res = await this.db.menu.delete({id : id})
        return res === 0 ? this.failRes() : this.successRes()
    }
}
